package org.libra.managers {
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import org.libra.basic.Component;
	import org.libra.basic.Container;
	
	/**
	 * 拖放管理类
	 * @author zhangzuoqiang
	 */
	public final class DragManager {
		
		public static var isDraging:Boolean = false;
		
		/**
		 * 文档类
		 */
		private static var main:DisplayObjectContainer;
		
		/**
		 * 响应鼠标事件的托。
		 */
		private static var dragSprite:Sprite;
		
		/**
		 * 拖动组件时呈现的Bitmap
		 * 只要修改其bitmapData，就能呈现出不同的图案
		 */
		private static var dragBitmap:Bitmap;
		
		/**
		 * 被拖放的组件
		 */
		private static var dragInitiator:Component;
		
		/**
		 * 放下组件时，该组件是否能被对应的容易接受
		 */
		private static var dropable:Boolean;
		
		/**
		 * 开始拖动组件时的坐标
		 */
		private static var startPoint:Point;
		
		/**
		 * 被拒绝的动画中组件的移动速度
		 */
		private static var speed:Number = .25;;
		
		/**
		 * 无法实例化
		 */
		public function DragManager() {
			throw new Error("DragManager can not be instance!");
		}
		
		/**
		 * 设置文档类并进行初始化
		 * @param	main 文档类
		 */
		public static function setMain(main:DisplayObjectContainer):void {
			DragManager.main = main;
			dragSprite = new Sprite();
			dragSprite.mouseEnabled = false;
			dragBitmap = new Bitmap();
			dragSprite.addChild(dragBitmap);
		}
		
		/**
		 * 开始拖动组件
		 * @param	dragInitiator
		 */
		public static function startDrag(dragInitiator:Component):void {
			if (isDraging) {
				return;
			}
			DragManager.dragInitiator = dragInitiator;
			isDraging = true;
			//获取组件拖动时的bitmapdata
			dragBitmap.bitmapData = dragInitiator.getDragBmd();
			dropable = true;
			setDropable(false);
			startPoint = dragInitiator.localToGlobal(new Point());
			dragSprite.x = startPoint.x;
			dragSprite.y = startPoint.y;
			main.addChild(dragSprite);
			dragSprite.startDrag();
			main.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
			main.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
		}
		
		/**
		 * 停止拖动，播放动画
		 */
		public static function stopDrag():void {
			if (isDraging) {
				main.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
				main.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
				dragSprite.stopDrag();
				playMotion();
			}
		}
		
		/**
		 * 播放动画
		 */
		static private function playMotion():void {
			if (dropable) {
				//如果成功拖放了，就直接移除拖放图案的托
				main.removeChild(dragSprite);
				isDraging = false;
			}else {
				//如果组件不被容易所接受，那么播放失败动画
				dragSprite.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
			}
		}
		
		/**
		 * 播放失败的动画
		 * @param	e
		 */
		static private function onEnterFrameHandler(e:Event):void {
			var p:Point = main.localToGlobal(new Point(dragSprite.x, dragSprite.y));
			p.x += (startPoint.x - p.x) * speed;
			p.y += (startPoint.y - p.y) * speed;
			if (Point.distance(p, startPoint) < 2) { 
				dragSprite.removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
				dragSprite.alpha = 1;
				main.removeChild(dragSprite);
				isDraging = false;
				return;
			}
			dragSprite.x = p.x;
			dragSprite.y = p.y;
		}
		
		/**
		 * 鼠标弹起后，停止拖放
		 * @param	e
		 */
		static private function onMouseUpHandler(e:MouseEvent):void {
			stopDrag();
		}
		
		/**
		 * 鼠标移动时，判断组件对应的容器是否接受该组件
		 * @param	e
		 */
		static private function onMouseMoveHandler(e:MouseEvent):void {
			var container:Container = getAcceptContainer(new Point(e.stageX, e.stageY));
			if (container) {
				setDropable(true);
			}else {
				setDropable(false);
			}
		}
		
		/**
		 * 获取当前鼠标坐标下的容器
		 * @param	pos 当前鼠标坐标
		 * @return 容器
		 */
		private static function getAcceptContainer(pos:Point):Container {
			var targets:Array = main.stage.getObjectsUnderPoint(pos);
			var n:int = targets.length;
			for (var i:int = n - 1; i >= 0; i--) { 
				var tar:DisplayObject = targets[i];
				if (tar is Container) { 
					var con:Container = tar as Container;
					if (con.isDragAcceptableInitiator(dragInitiator)) {
						return con;
					}
				}
			}
			return null;
		}
		
		/**
		 * 设置拖动中的组件是否可以被对应容器所接受
		 * @param	b true：可以，false：不可以
		 */
		private static function setDropable(b:Boolean):void { 
			if (dropable != b) {
				dropable = b;
				if (b) {
					dragSprite.alpha = 1;
				}else {
					dragSprite.alpha = .5;
				}
			}
		}
		
	}

}